<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  <title>Mina系列四之IoService | Hexo</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="description" content="简介　　IoAcceptor 和 IoConnector 均继承自IoService，它是mina的核心组件，提供标准的I/O 服务并且管理I/O 会话Session。IoService为大部分mina服务提供了底层的API支持，IoService的职责主要包括：　　1. 会话Session管理：创建和销毁会话，检测session等待等。　　2. 过滤器链管理：管理过滤器链，提供多个切面的服务，并">
<meta property="og:type" content="article">
<meta property="og:title" content="Mina系列四之IoService">
<meta property="og:url" content="http://yoursite.com/2016/01/19/nio/18.Mina系列四之IoService/index.html">
<meta property="og:site_name" content="Hexo">
<meta property="og:description" content="简介　　IoAcceptor 和 IoConnector 均继承自IoService，它是mina的核心组件，提供标准的I/O 服务并且管理I/O 会话Session。IoService为大部分mina服务提供了底层的API支持，IoService的职责主要包括：　　1. 会话Session管理：创建和销毁会话，检测session等待等。　　2. 过滤器链管理：管理过滤器链，提供多个切面的服务，并">
<meta property="og:image" content="http://yoursite.com/images/mina-uml-server.jpg">
<meta property="og:image" content="http://yoursite.com/images/mina-thread.png">
<meta property="og:updated_time" content="2016-01-29T17:47:36.000Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Mina系列四之IoService">
<meta name="twitter:description" content="简介　　IoAcceptor 和 IoConnector 均继承自IoService，它是mina的核心组件，提供标准的I/O 服务并且管理I/O 会话Session。IoService为大部分mina服务提供了底层的API支持，IoService的职责主要包括：　　1. 会话Session管理：创建和销毁会话，检测session等待等。　　2. 过滤器链管理：管理过滤器链，提供多个切面的服务，并">
  
    <link rel="alternative" href="/atom.xml" title="Hexo" type="application/atom+xml">
  
  
    <link rel="icon" href="/favicon.png">
  
  <link href="//fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
  <link rel="stylesheet" href="/css/style.css" type="text/css">
  

</head>
<body>
  <div id="container">
    <div id="wrap">
      <header id="header">
  <div id="banner"></div>
  <div id="header-outer" class="outer">
    <div id="header-title" class="inner">
      <h1 id="logo-wrap">
        <a href="/" id="logo">Hexo</a>
      </h1>
      
    </div>
    <div id="header-inner" class="inner">
      <nav id="main-nav">
        <a id="main-nav-toggle" class="nav-icon"></a>
        
          <a class="main-nav-link" href="/">Home</a>
        
          <a class="main-nav-link" href="/archives">Archives</a>
        
      </nav>
      <nav id="sub-nav">
        
          <a id="nav-rss-link" class="nav-icon" href="/atom.xml" title="RSS Feed"></a>
        
        <a id="nav-search-btn" class="nav-icon" title="Search"></a>
      </nav>
      <div id="search-form-wrap">
        <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" results="0" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit">&#xF002;</button><input type="hidden" name="sitesearch" value="http://yoursite.com"></form>
      </div>
    </div>
  </div>
</header>
      <div class="outer">
        <section id="main"><article id="post-nio/18.Mina系列四之IoService" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2016/01/19/nio/18.Mina系列四之IoService/" class="article-date">
  <time datetime="2016-01-19T06:04:00.000Z" itemprop="datePublished">2016-01-19</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/nio/">nio</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 class="article-title" itemprop="name">
      Mina系列四之IoService
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h2><p>　　IoAcceptor 和 IoConnector 均继承自IoService，它是mina的核心组件，提供标准的I/O 服务并且管理I/O 会话Session。IoService为大部分mina服务提供了底层的API支持，IoService的职责主要包括：<br>　　1. 会话Session管理：创建和销毁会话，检测session等待等。<br>　　2. 过滤器链管理：管理过滤器链，提供多个切面的服务，并允许用户在运行时动态变更过滤器链。<br>　　3. 处理调用：当有新消息或其他session生命周期触发事件响应时，回调用户的业务代码。<br>　　4. 统计管理：更新消息发送量、字节发送量等等信息。<br>　　5. 监听器管理：提供服务各个生命周期触发时间的监听器管理，如服务有效时、服务空闲时、会话创建时等。<br>　　6. 传输管理：可在服务端客户端有效的控制数据流的传输，平衡负载。<br>　　我们先看看服务端对IoService的实现，如下图所示：<img src="/images/mina-uml-server.jpg" alt="服务端UML"><br>　　服务端对nio的封装主要涉及上图左侧的几个类：AbstractIoService、AbstractIoAcceptor、AbstractPollingIoAcceptor和NioSocketAcceptor，下面我们依次说说这几个类的关键之处！</p>
<h2 id="AbstractIoService"><a href="#AbstractIoService" class="headerlink" title="AbstractIoService"></a>AbstractIoService</h2><p>　　AbstractIoService最重要几处便是构造方法的两个参数IoSessionConfig和Executor，它们是由父类的构造函数传递过来的，后面再详细讲解。还需要注意的就是其executeWorker方法，负责向Executor中添加Runnable，这个Runnable的生成也放到后面说明！<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">AbstractIoService</span> <span class="keyword">implements</span> <span class="title">IoService</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> AtomicInteger id = <span class="keyword">new</span> AtomicInteger();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> String threadName;</span><br><span class="line">    <span class="comment">//负责处理I/O事件</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Executor executor;</span><br><span class="line">	</span><br><span class="line">    <span class="keyword">private</span> IoHandler handler;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">final</span> IoSessionConfig sessionConfig;</span><br><span class="line">    <span class="keyword">private</span> IoFilterChainBuilder filterChainBuilder = <span class="keyword">new</span> DefaultIoFilterChainBuilder();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="title">AbstractIoService</span><span class="params">(IoSessionConfig sessionConfig, Executor executor)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.sessionConfig = sessionConfig;</span><br><span class="line">        <span class="keyword">this</span>.executor = Executors.newCachedThreadPool();</span><br><span class="line">        createdExecutor = <span class="keyword">true</span>;</span><br><span class="line">        threadName = getClass().getSimpleName() + <span class="string">'-'</span> + id.incrementAndGet();</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">executeWorker</span><span class="params">(Runnable worker, String suffix)</span> </span>&#123;</span><br><span class="line">        String actualThreadName = threadName;</span><br><span class="line">        <span class="keyword">if</span> (suffix != <span class="keyword">null</span>) &#123;</span><br><span class="line">            actualThreadName = actualThreadName + <span class="string">'-'</span> + suffix;</span><br><span class="line">        &#125;</span><br><span class="line">        executor.execute(<span class="keyword">new</span> NamePreservingRunnable(worker, actualThreadName));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">initSession</span><span class="params">(IoSession session, IoFuture future, IoSessionInitializer sessionInitializer)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (sessionInitializer != <span class="keyword">null</span>) &#123;</span><br><span class="line">            sessionInitializer.initializeSession(session, future);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="AbstractIoAcceptor"><a href="#AbstractIoAcceptor" class="headerlink" title="AbstractIoAcceptor"></a>AbstractIoAcceptor</h2><p>　　我们开发的MinaTimeServer中，调用了NioSocketAcceptor的bind方法，实际上是在AbstractIoService中声明的。这里需要注意的一个点就是：mina在设计的时候考虑了<strong>服务器可能会有多个网卡的问题</strong>，详见bind的重载方法！<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">AbstractIoAcceptor</span> <span class="keyword">extends</span> <span class="title">AbstractIoService</span> <span class="keyword">implements</span> <span class="title">IoAcceptor</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="title">AbstractIoAcceptor</span><span class="params">(IoSessionConfig sessionConfig, Executor executor)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>(sessionConfig, executor);</span><br><span class="line">        defaultLocalAddresses.add(<span class="keyword">null</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">bind</span><span class="params">(SocketAddress localAddress)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">        List&lt;SocketAddress&gt; localAddresses = <span class="keyword">new</span> ArrayList&lt;SocketAddress&gt;(<span class="number">1</span>);</span><br><span class="line">        localAddresses.add(localAddress);</span><br><span class="line">        bind(localAddresses);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">bind</span><span class="params">(Iterable&lt;? extends SocketAddress&gt; localAddresses)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">        List&lt;SocketAddress&gt; localAddressesCopy = <span class="keyword">new</span> ArrayList&lt;SocketAddress&gt;();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (SocketAddress a : localAddresses) &#123;</span><br><span class="line">            localAddressesCopy.add(a);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">synchronized</span> (bindLock) &#123;</span><br><span class="line">            Set&lt;SocketAddress&gt; addresses = bindInternal(localAddressesCopy);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">abstract</span> Set&lt;SocketAddress&gt; <span class="title">bindInternal</span><span class="params">(List&lt;? extends SocketAddress&gt; localAddresses)</span> <span class="keyword">throws</span> Exception</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　可以看到最后实际执行了抽象方法bindInternal，下面我们看看AbstractPollingIoAcceptor对bindInternal方法的实现</p>
<h2 id="AbstractPollingIoAcceptor"><a href="#AbstractPollingIoAcceptor" class="headerlink" title="AbstractPollingIoAcceptor"></a>AbstractPollingIoAcceptor</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">AbstractPollingIoAcceptor</span>&lt;<span class="title">S</span> <span class="keyword">extends</span> <span class="title">AbstractIoSession</span>, <span class="title">H</span>&gt; <span class="keyword">extends</span> <span class="title">AbstractIoAcceptor</span> </span>&#123;</span><br><span class="line">    <span class="comment">//默认为SimpleIoProcessorPool</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> IoProcessor&lt;S&gt; processor;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">boolean</span> createdProcessor;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">volatile</span> <span class="keyword">boolean</span> selectable;</span><br><span class="line">    <span class="keyword">private</span> AtomicReference&lt;Acceptor&gt; acceptorRef = <span class="keyword">new</span> AtomicReference&lt;Acceptor&gt;();</span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">boolean</span> reuseAddress = <span class="keyword">false</span>;</span><br><span class="line"></span><br><span class="line">	<span class="comment">//默认传入的为NioProcessor</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="title">AbstractPollingIoAcceptor</span><span class="params">(IoSessionConfig sessionConfig, Class&lt;? extends IoProcessor&lt;S&gt;&gt; processorClass)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>(sessionConfig, <span class="keyword">null</span>, <span class="keyword">new</span> SimpleIoProcessorPool&lt;S&gt;(processorClass), <span class="keyword">true</span>, <span class="keyword">null</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="title">AbstractPollingIoAcceptor</span><span class="params">(IoSessionConfig sessionConfig, Executor executor, IoProcessor&lt;S&gt; processor,</span><br><span class="line">            <span class="keyword">boolean</span> createdProcessor, SelectorProvider selectorProvider)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>(sessionConfig, executor);</span><br><span class="line">        <span class="keyword">this</span>.processor = processor;</span><br><span class="line">        <span class="keyword">this</span>.createdProcessor = createdProcessor;</span><br><span class="line">        init(selectorProvider);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">()</span> <span class="keyword">throws</span> Exception</span>;</span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">abstract</span> <span class="keyword">int</span> <span class="title">select</span><span class="params">()</span> <span class="keyword">throws</span> Exception</span>;</span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title">wakeup</span><span class="params">()</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">abstract</span> H <span class="title">open</span><span class="params">(SocketAddress localAddress)</span> <span class="keyword">throws</span> Exception</span>;</span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">abstract</span> S <span class="title">accept</span><span class="params">(IoProcessor&lt;S&gt; processor, H handle)</span> <span class="keyword">throws</span> Exception</span>;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">final</span> Set&lt;SocketAddress&gt; <span class="title">bindInternal</span><span class="params">(List&lt;? extends SocketAddress&gt; localAddresses)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        startupAcceptor();</span><br><span class="line">        lock.acquire();</span><br><span class="line">        <span class="comment">// Wait a bit to give a chance to the Acceptor thread to do the select()</span></span><br><span class="line">        Thread.sleep(<span class="number">10</span>);</span><br><span class="line">        wakeup();</span><br><span class="line">        lock.release();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">startupAcceptor</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        Acceptor acceptor = acceptorRef.get();</span><br><span class="line">        <span class="keyword">if</span> (acceptor == <span class="keyword">null</span>) &#123;</span><br><span class="line">            lock.acquire();</span><br><span class="line">            acceptor = <span class="keyword">new</span> Acceptor();</span><br><span class="line">            <span class="keyword">if</span> (acceptorRef.compareAndSet(<span class="keyword">null</span>, acceptor)) &#123;</span><br><span class="line">                executeWorker(acceptor);</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                lock.release();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//打开ServerSocketChannel</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">int</span> <span class="title">registerHandles</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">for</span> (;;) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="keyword">for</span> (SocketAddress a : localAddresses) &#123;</span><br><span class="line">                    H handle = open(a);</span><br><span class="line">                    newHandles.put(localAddress(handle), handle);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            &#125; <span class="keyword">finally</span> &#123;&#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">Acceptor</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">int</span> nHandles = <span class="number">0</span>;</span><br><span class="line">            lock.release();</span><br><span class="line">            <span class="keyword">while</span> (selectable) &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    <span class="keyword">int</span> selected = select();</span><br><span class="line">                    nHandles += registerHandles();</span><br><span class="line">                    <span class="keyword">if</span> (selected &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                        processHandles(selectedHandles());</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">processHandles</span><span class="params">(Iterator&lt;H&gt; handles)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">            <span class="keyword">while</span> (handles.hasNext()) &#123;</span><br><span class="line">                H handle = handles.next();</span><br><span class="line">                handles.remove();</span><br><span class="line"></span><br><span class="line">                S session = accept(processor, handle);</span><br><span class="line">                initSession(session, <span class="keyword">null</span>, <span class="keyword">null</span>);</span><br><span class="line"></span><br><span class="line">                session.getProcessor().add(session);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>　　可以看到，bindInternal最终执行了 startupAcceptor 方法，该方法将其内部类 Acceptor 实例（一个Runnable）放到了AbstractIoService中的的Executor中执行！<br>　　Acceptor 的run方法调用了抽象方法select、registerHandles(它又调用了抽象方法open)，如果selected&gt;0，则还会调用accept方法，下面我们进入NioSocketAcceptor看看其对select、open和accept等方法的实现！</p>
<h2 id="NioSocketAcceptor"><a href="#NioSocketAcceptor" class="headerlink" title="NioSocketAcceptor"></a>NioSocketAcceptor</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">NioSocketAcceptor</span> <span class="keyword">extends</span> <span class="title">AbstractPollingIoAcceptor</span>&lt;<span class="title">NioSession</span>, <span class="title">ServerSocketChannel</span>&gt; <span class="keyword">implements</span> <span class="title">SocketAcceptor</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">volatile</span> Selector selector;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">NioSocketAcceptor</span><span class="params">(<span class="keyword">int</span> processorCount)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>(<span class="keyword">new</span> DefaultSocketSessionConfig(), NioProcessor.class, processorCount);</span><br><span class="line">        ((DefaultSocketSessionConfig) getSessionConfig()).init(<span class="keyword">this</span>);</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        selector = Selector.open();</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> NioSession <span class="title">accept</span><span class="params">(IoProcessor&lt;NioSession&gt; processor, ServerSocketChannel handle)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        SocketChannel ch = handle.accept();</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> NioSocketSession(<span class="keyword">this</span>, processor, ch);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> ServerSocketChannel <span class="title">open</span><span class="params">(SocketAddress localAddress)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line"></span><br><span class="line">        ServerSocketChannel channel = ServerSocketChannel.open();</span><br><span class="line">        channel.configureBlocking(<span class="keyword">false</span>);</span><br><span class="line">        ServerSocket socket = channel.socket();</span><br><span class="line">        socket.setReuseAddress(isReuseAddress());</span><br><span class="line"></span><br><span class="line">        socket.bind(localAddress, getBacklog());</span><br><span class="line"></span><br><span class="line">        <span class="comment">// ServerSocketChannel的interests为OP_ACCEPT，即监听客户端的连接事件</span></span><br><span class="line">        channel.register(selector, SelectionKey.OP_ACCEPT);</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">return</span> channel;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">int</span> <span class="title">select</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> selector.select();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">wakeup</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        selector.wakeup();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>　　可以看到，上面这些方法的实现就是对原生NIO的一个简单包装罢了，到这里我们基本上可以理解IoAcceptor对客户端连接事件的处理流程：<br>　　1. 业务代码对 NioSocketAcceptor.bind 方法的调用最终导致了AbstractPollingIoAcceptor的内部类Acceptor的执行<br>　　2. Acceptor是一个Runnable，其会在Executors中执行，而Executors则是在AbstractIoService的构造方法中初始化：executor = Executors.newCachedThreadPool()<br>　　3. Acceptor的run方法会导致NioSocketAcceptor中select、open和accept等方法的执行<br>　　4. NioSocketAcceptor内部维护了一个Selector，执行open方法时会将ServerSocketChannel注册到其中，并监听OP_ACCEPT事件<br>　　5. 当有新的客户端连接时，OP_ACCEPT事件被触发，得到一个SocketChanel，并将其和SimpleIoProcessorPool、NioSocketAcceptor一起封装到NioSocketSession中<br>　　第五点提到了SimpleIoProcessorPool，它是个什么东西呢，继续看下文！</p>
<h2 id="SimpleIoProcessorPool"><a href="#SimpleIoProcessorPool" class="headerlink" title="SimpleIoProcessorPool"></a>SimpleIoProcessorPool</h2><p>　　之前我们提到NioSocketAcceptor中的Selector只监听了ServerSocketChannel的OP_ACCEPT事件，客户端连接得到的SocketChanel封装到session返回，但是并没有注册其读写事件到selecotr中，此时我们先看看Acceptor中的processHandles方法！<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">processHandles</span><span class="params">(Iterator&lt;H&gt; handles)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">	<span class="keyword">while</span> (handles.hasNext()) &#123;</span><br><span class="line">        H handle = handles.next();</span><br><span class="line">        handles.remove();</span><br><span class="line">        </span><br><span class="line">        S session = accept(processor, handle);</span><br><span class="line">        initSession(session, <span class="keyword">null</span>, <span class="keyword">null</span>);</span><br><span class="line">        <span class="comment">//重点关注此行代码的执行</span></span><br><span class="line">        session.getProcessor().add(session);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　之前我们提到过session初始化时会传入SimpleIoProcessorPool，所示session.getProcessor().add(session)最终执行的是SimpleIoProcessorPool的add方法，下面我们看看SimpleIoProcessorPool的关键代码！<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SimpleIoProcessorPool</span>&lt;<span class="title">S</span> <span class="keyword">extends</span> <span class="title">AbstractIoSession</span>&gt; <span class="keyword">implements</span> <span class="title">IoProcessor</span>&lt;<span class="title">S</span>&gt; </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/** 线程池的大小，默认为cpu核数+1 */</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> DEFAULT_SIZE = Runtime.getRuntime().availableProcessors() + <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> AttributeKey PROCESSOR = <span class="keyword">new</span> AttributeKey(SimpleIoProcessorPool.class, <span class="string">"processor"</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> IoProcessor&lt;S&gt;[] pool;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Executor executor;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">boolean</span> createdExecutor;</span><br><span class="line">    <span class="comment">//示例代码中processorType参数默认为NioProcesor、executor为null</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">SimpleIoProcessorPool</span><span class="params">(Class&lt;? extends IoProcessor&lt;S&gt;&gt; processorType, Executor executor, <span class="keyword">int</span> size, SelectorProvider selectorProvider)</span> </span>&#123;</span><br><span class="line">        createdExecutor = (executor == <span class="keyword">null</span>);</span><br><span class="line">        <span class="keyword">if</span> (createdExecutor) &#123;</span><br><span class="line">            <span class="keyword">this</span>.executor = Executors.newCachedThreadPool();</span><br><span class="line">            ((ThreadPoolExecutor) <span class="keyword">this</span>.executor).setRejectedExecutionHandler(<span class="keyword">new</span> ThreadPoolExecutor.CallerRunsPolicy());</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">this</span>.executor = executor;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        pool = <span class="keyword">new</span> IoProcessor[size];</span><br><span class="line"></span><br><span class="line">        <span class="keyword">boolean</span> success = <span class="keyword">false</span>;</span><br><span class="line">        Constructor&lt;? extends IoProcessor&lt;S&gt;&gt; processorConstructor = <span class="keyword">null</span>;</span><br><span class="line">        <span class="keyword">boolean</span> usesExecutorArg = <span class="keyword">true</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    <span class="comment">//先初始化第一个IoProcessor</span></span><br><span class="line">                    processorConstructor = processorType.getConstructor(ExecutorService.class);</span><br><span class="line">                    pool[<span class="number">0</span>] = processorConstructor.newInstance(<span class="keyword">this</span>.executor);</span><br><span class="line">                &#125; <span class="keyword">catch</span> (NoSuchMethodException e1) &#123;</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        <span class="comment">//如果失败则采用其他的构造函数</span></span><br><span class="line">                        processorConstructor = processorType.getConstructor(Executor.class);</span><br><span class="line">                        pool[<span class="number">0</span>] = processorConstructor.newInstance(<span class="keyword">this</span>.executor);</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (NoSuchMethodException e2) &#123;</span><br><span class="line">                        <span class="comment">//最后采用默认的构造函数</span></span><br><span class="line">                        processorConstructor = processorType.getConstructor();</span><br><span class="line">                        pool[<span class="number">0</span>] = processorConstructor.newInstance();</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">catch</span> (RuntimeException re) &#123;&#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 接着初始化线程池中剩余的IoProcessor</span></span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt; pool.length; i++) &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    <span class="keyword">if</span> (usesExecutorArg) &#123;</span><br><span class="line">                        pool[i] = processorConstructor.newInstance(<span class="keyword">this</span>.executor);</span><br><span class="line">                    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                        pool[i] = processorConstructor.newInstance();</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125; <span class="keyword">catch</span> (Exception e) &#123;&#125;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            success = <span class="keyword">true</span>;</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;&#125;</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">add</span><span class="params">(S session)</span> </span>&#123;</span><br><span class="line">        getProcessor(session).add(session);</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">flush</span><span class="params">(S session)</span> </span>&#123;</span><br><span class="line">        getProcessor(session).flush(session);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">write</span><span class="params">(S session, WriteRequest writeRequest)</span> </span>&#123;</span><br><span class="line">        getProcessor(session).write(session, writeRequest);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">remove</span><span class="params">(S session)</span> </span>&#123;</span><br><span class="line">        getProcessor(session).remove(session);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">updateTrafficControl</span><span class="params">(S session)</span> </span>&#123;</span><br><span class="line">        getProcessor(session).updateTrafficControl(session);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> IoProcessor&lt;S&gt; <span class="title">getProcessor</span><span class="params">(S session)</span> </span>&#123;</span><br><span class="line">        IoProcessor&lt;S&gt; processor = (IoProcessor&lt;S&gt;) session.getAttribute(PROCESSOR);</span><br><span class="line">        <span class="keyword">if</span> (processor == <span class="keyword">null</span>) &#123;</span><br><span class="line">            processor = pool[Math.abs((<span class="keyword">int</span>) session.getId()) % pool.length];</span><br><span class="line">            session.setAttributeIfAbsent(PROCESSOR, processor);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> processor;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　SimpleIoProcessorPool初始化过程请详见代码中的注释，这里不在介绍。我们注意到，在其add方法内部，会调用getProcessor方法，从池中选取一个IoProcessor（实际为NioProcessor），并将新生成的session放到该NioProcessor中，实际执行的是其父类AbstractPollingIoProcessor的add方法。NioProcessor类的层次结构为： NioProcessor =&gt; AbstractPollingIoProcessor =&gt; IoProcessor，这里我们直接对这几个类做简要的介绍：<br>　　1. NioProcessor中维护了一个java.nio.channels.Selector，初始化时打开该Selector<br>　　2. AbstractPollingIoProcessor维护了一个内部类Processor，与IoAcceptor中的类似，也是一个Runnable<br>　　3. 每次调用AbstractPollingIoProcessor.add方法添加新的session时，先将session放入一个ConcurrentLinkedQueue中，再新建一个Processor（如果之前没有新建过）放到Executor中执行<br>　　4. mina会在Processor的run方法中，将session的SocketChannel注册到NioProcessor的Selector中，监听OP_READ事件<br>　　5. 同时也会在Processor的run方法中，进行I/O的读写操作<br>　　可以看到，Processor线程主要<strong>负责IO读写操作和执行后面的IoFilterChain和IoHandler逻辑</strong>。Processor线程的数量N默认是CPU数量+1，可以通过配置参数来控制其数量，前面进来的IoSession会被分配到这N个Processor线程中。<br>　　每个Porcessor线程中都维护着一个selector，对它维护的IoSession集合进行select，然后对select的结果进行遍历，逐一处理。像前面提到的，读取数据，以事件的形式通知后面IoFilterChain；以及对写请求队列的flush操作，都是在这类线程中来做的。<br>　　通过将session均分到多个Processor线程里进行处理，可以充分利用多核的处理能力，减轻select操作的压力。但是这样有一个问题：<strong>从单一的Processor线程来看，IO请求的处理流程是单线程顺序处理的。当Process线程select了一批就绪的IO请求后，会在线程内部逐一对这些IO请求进行处理。处理的流程包括IoFilter和IoHandler里的逻辑。当前面的IO请求处理完毕后，才会取下一个IO请求进行处理。如果IoFilter或IoHandler中有比较耗时的操作，Processor线程将会被阻塞住，后续的请求将得不到处理</strong>。这样的情况在高并发的服务器下显然是不能容忍的。于是，Mina通过IoFilter的形式来为处理流程添加线程池。Mina的线程模型主要有以下几种形式：![processor-thread](/images/processor-thread.png<br>　　第一种模型是单线程模型，也是Mina默认线程模型。也就是Processor包办了从底层IO到上层的IoHandler逻辑的所有执行工作。这种模型比较适合于处理逻辑简单，能快速返回的情况。<br>　　第二种模型则是在IoFilterChain中加入了Thread Pool Filter。此时的处理流程变为Processor线程读取完数据后，执行IoFilterChain的逻辑。当执行到Thread Pool Filter的时候，该Filter会将后续的处理流程封装到一个Runnable对象中，并交由Filter自身的线程池来执行，而Processor线程则能立即返回来处理下一个IO请求。这样如果后面的IoFilter或IoHandler中有阻塞操作，只会引起Filter线程池里的线程阻塞，而不会阻塞住Processor线程，从而提高了服务器的处理能力。Mina提供了Thread Pool Filter的一个实现：ExecutorFilter。<br>　　当然，也没有限制说chain中只能添加一个ExecutorFilter，开发者也可以在chain中加入多个ExecutorFilter来构成第三种情况，但一般情况下可能没有这个必要。</p>
<h2 id="IoConnector"><a href="#IoConnector" class="headerlink" title="IoConnector"></a>IoConnector</h2><p>　　上面提到，在服务器端bind一个端口后，会创建一个Acceptor线程来负责监听工作。这个线程的工作只有一个，调用Java NIO接口在该端口上select connect事件，获取新建的连接后，封装成IoSession，交由后面的Processor线程处理。<br>　　在客户端，也有一个叫Connector的线程与之相对应。这两类线程的数量只有1个，外界无法控制这两类线程的数量。具体的源码分析以后再完善！</p>
<h2 id="u603B_u7ED3"><a href="#u603B_u7ED3" class="headerlink" title="总结"></a>总结</h2><p>　　1. IoAcceptor中的selector只注册了ServerSocketChannel，负责处理客户端的连接事件<br>　　2. IoProcessor中的selector注册了N个SocketChannel，负责处理tcp连接的数据读写，一个IoProcessor负责维护多个客户端的连接。IoProcessor的个数默认为cup核数+1<br>　　3. 通过以上方式，实现了客户端连接和io读写的事件分离，将连接和业务处理分开，以得到较高的处理性能！<br>　　通过下图基本可以概括mina的线程调度原理：<img src="/images/mina-thread.png" alt="线程调度原理"></p>
<h2 id="u53C2_u8003_u94FE_u63A5"><a href="#u53C2_u8003_u94FE_u63A5" class="headerlink" title="参考链接"></a>参考链接</h2><p><a href="http://blog.csdn.net/yoara/article/details/37382137" target="_blank" rel="external">http://blog.csdn.net/yoara/article/details/37382137</a><br><a href="http://www.iteye.com/topic/1125178" target="_blank" rel="external">http://www.iteye.com/topic/1125178</a><br><a href="http://www.tuicool.com/articles/eUzUja" target="_blank" rel="external">http://www.tuicool.com/articles/eUzUja</a><br><a href="http://www.cnblogs.com/phinecos/archive/2008/12/03/1347052.html" target="_blank" rel="external">http://www.cnblogs.com/phinecos/archive/2008/12/03/1347052.html</a><br><a href="http://www.tuicool.com/articles/Ujeum2" target="_blank" rel="external">http://www.tuicool.com/articles/Ujeum2</a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2016/01/19/nio/18.Mina系列四之IoService/" data-id="cijzzpv79005i1cfsl75fipp5" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/mina/">mina</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/nio/">nio</a></li></ul>

    </footer>
  </div>
  
    
<nav id="article-nav">
  
    <a href="/2016/01/21/spring/2.spring事物传播机制/" id="article-nav-newer" class="article-nav-link-wrap">
      <strong class="article-nav-caption">Newer</strong>
      <div class="article-nav-title">
        
          spring事务传播机制
        
      </div>
    </a>
  
  
    <a href="/2016/01/18/nio/17.Mina系列三之IoFilter/" id="article-nav-older" class="article-nav-link-wrap">
      <strong class="article-nav-caption">Older</strong>
      <div class="article-nav-title">Mina系列三之IoFilter</div>
    </a>
  
</nav>

  
</article>

</section>
        
          <aside id="sidebar">
  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Categories</h3>
    <div class="widget">
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/cache/">cache</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/database/">database</a><span class="category-list-count">13</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/docker/">docker</a><span class="category-list-count">6</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/gis/">gis</a><span class="category-list-count">4</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/git/">git</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/go/">go</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/gradle/">gradle</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/groovy/">groovy</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/hadoop/">hadoop</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/java/">java</a><span class="category-list-count">18</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/linux/">linux</a><span class="category-list-count">4</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/log/">log</a><span class="category-list-count">11</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/mongodb/">mongodb</a><span class="category-list-count">14</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/mq/">mq</a><span class="category-list-count">6</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/mybatis/">mybatis</a><span class="category-list-count">9</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/netty/">netty</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/nginx/">nginx</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/nio/">nio</a><span class="category-list-count">19</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/nodejs/">nodejs</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/redis/">redis</a><span class="category-list-count">6</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/rpc/">rpc</a><span class="category-list-count">14</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/spring/">spring</a><span class="category-list-count">5</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/tomcat/">tomcat</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/zookeeper/">zookeeper</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/杂项/">杂项</a><span class="category-list-count">2</span></li></ul>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tags</h3>
    <div class="widget">
      <ul class="tag-list"><li class="tag-list-item"><a class="tag-list-link" href="/tags/aop/">aop</a><span class="tag-list-count">8</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/aspectj/">aspectj</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/cache/">cache</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/classloader/">classloader</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/common-loggings/">common-loggings</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/commonjs/">commonjs</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/database/">database</a><span class="tag-list-count">10</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/docker/">docker</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/dubbo/">dubbo</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/fastdfs/">fastdfs</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/gclib/">gclib</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/geohash/">geohash</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/gis/">gis</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/git/">git</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/go/">go</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/gradle/">gradle</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/groovy/">groovy</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/hadoop/">hadoop</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/hessisan/">hessisan</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/java/">java</a><span class="tag-list-count">48</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/javassist/">javassist</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/kafka/">kafka</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/linux/">linux</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/log/">log</a><span class="tag-list-count">11</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/log4j/">log4j</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/logback/">logback</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/map/">map</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/memecached/">memecached</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mina/">mina</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mongodb/">mongodb</a><span class="tag-list-count">14</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mq/">mq</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mqtt/">mqtt</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mybatis/">mybatis</a><span class="tag-list-count">9</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/netty/">netty</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nginx/">nginx</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nio/">nio</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nodejs/">nodejs</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/postgresql/">postgresql</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/protobuf/">protobuf</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/proxy/">proxy</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/push/">push</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/rabbitmq/">rabbitmq</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/redis/">redis</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/rpc/">rpc</a><span class="tag-list-count">14</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/sitemesh/">sitemesh</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/sld/">sld</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/slf4j/">slf4j</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/socket/">socket</a><span class="tag-list-count">7</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spatialite-for-android/">spatialite for android</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spi/">spi</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spring/">spring</a><span class="tag-list-count">13</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/tomcat/">tomcat</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/transaction/">transaction</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/web/">web</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/xSocket/">xSocket</a><span class="tag-list-count">7</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/zbus/">zbus</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/zookeeper/">zookeeper</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/数据结构/">数据结构</a><span class="tag-list-count">2</span></li></ul>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tag Cloud</h3>
    <div class="widget tagcloud">
      <a href="/tags/aop/" style="font-size: 15.38px;">aop</a> <a href="/tags/aspectj/" style="font-size: 11.54px;">aspectj</a> <a href="/tags/cache/" style="font-size: 11.54px;">cache</a> <a href="/tags/classloader/" style="font-size: 10px;">classloader</a> <a href="/tags/common-loggings/" style="font-size: 10px;">common-loggings</a> <a href="/tags/commonjs/" style="font-size: 12.31px;">commonjs</a> <a href="/tags/database/" style="font-size: 16.92px;">database</a> <a href="/tags/docker/" style="font-size: 13.85px;">docker</a> <a href="/tags/dubbo/" style="font-size: 10px;">dubbo</a> <a href="/tags/fastdfs/" style="font-size: 10px;">fastdfs</a> <a href="/tags/gclib/" style="font-size: 10.77px;">gclib</a> <a href="/tags/geohash/" style="font-size: 10px;">geohash</a> <a href="/tags/gis/" style="font-size: 10px;">gis</a> <a href="/tags/git/" style="font-size: 10.77px;">git</a> <a href="/tags/go/" style="font-size: 10px;">go</a> <a href="/tags/gradle/" style="font-size: 10px;">gradle</a> <a href="/tags/groovy/" style="font-size: 10px;">groovy</a> <a href="/tags/hadoop/" style="font-size: 10px;">hadoop</a> <a href="/tags/hessisan/" style="font-size: 11.54px;">hessisan</a> <a href="/tags/java/" style="font-size: 20px;">java</a> <a href="/tags/javassist/" style="font-size: 10px;">javassist</a> <a href="/tags/kafka/" style="font-size: 11.54px;">kafka</a> <a href="/tags/linux/" style="font-size: 12.31px;">linux</a> <a href="/tags/log/" style="font-size: 17.69px;">log</a> <a href="/tags/log4j/" style="font-size: 12.31px;">log4j</a> <a href="/tags/logback/" style="font-size: 13.08px;">logback</a> <a href="/tags/map/" style="font-size: 10px;">map</a> <a href="/tags/memecached/" style="font-size: 10.77px;">memecached</a> <a href="/tags/mina/" style="font-size: 13.08px;">mina</a> <a href="/tags/mongodb/" style="font-size: 19.23px;">mongodb</a> <a href="/tags/mq/" style="font-size: 13.85px;">mq</a> <a href="/tags/mqtt/" style="font-size: 10.77px;">mqtt</a> <a href="/tags/mybatis/" style="font-size: 16.15px;">mybatis</a> <a href="/tags/netty/" style="font-size: 10px;">netty</a> <a href="/tags/nginx/" style="font-size: 11.54px;">nginx</a> <a href="/tags/nio/" style="font-size: 13.08px;">nio</a> <a href="/tags/nodejs/" style="font-size: 10px;">nodejs</a> <a href="/tags/postgresql/" style="font-size: 10.77px;">postgresql</a> <a href="/tags/protobuf/" style="font-size: 10px;">protobuf</a> <a href="/tags/proxy/" style="font-size: 10px;">proxy</a> <a href="/tags/push/" style="font-size: 10px;">push</a> <a href="/tags/rabbitmq/" style="font-size: 11.54px;">rabbitmq</a> <a href="/tags/redis/" style="font-size: 13.85px;">redis</a> <a href="/tags/rpc/" style="font-size: 19.23px;">rpc</a> <a href="/tags/sitemesh/" style="font-size: 10px;">sitemesh</a> <a href="/tags/sld/" style="font-size: 10px;">sld</a> <a href="/tags/slf4j/" style="font-size: 10px;">slf4j</a> <a href="/tags/socket/" style="font-size: 14.62px;">socket</a> <a href="/tags/spatialite-for-android/" style="font-size: 10px;">spatialite for android</a> <a href="/tags/spi/" style="font-size: 10px;">spi</a> <a href="/tags/spring/" style="font-size: 18.46px;">spring</a> <a href="/tags/tomcat/" style="font-size: 10.77px;">tomcat</a> <a href="/tags/transaction/" style="font-size: 10px;">transaction</a> <a href="/tags/web/" style="font-size: 10px;">web</a> <a href="/tags/xSocket/" style="font-size: 14.62px;">xSocket</a> <a href="/tags/zbus/" style="font-size: 10px;">zbus</a> <a href="/tags/zookeeper/" style="font-size: 10.77px;">zookeeper</a> <a href="/tags/数据结构/" style="font-size: 10.77px;">数据结构</a>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Archives</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2016/01/">January 2016</a><span class="archive-list-count">67</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/12/">December 2015</a><span class="archive-list-count">81</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/11/">November 2015</a><span class="archive-list-count">2</span></li></ul>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Recents</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/2016/01/30/资料/">(no title)</a>
          </li>
        
          <li>
            <a href="/2016/01/30/java/13.Classloader系列一/">ClassLoader系列一</a>
          </li>
        
          <li>
            <a href="/2016/01/29/hadoop/1.hadoop系列之源码编译/">hadoop系列一之源码编译</a>
          </li>
        
          <li>
            <a href="/2016/01/29/go/1.GO系列之入门/">Go系列一之入门</a>
          </li>
        
          <li>
            <a href="/2016/01/28/tomcat/2.tomcat性能优化/">tomcat性能优化</a>
          </li>
        
      </ul>
    </div>
  </div>

  
</aside>
        
      </div>
      <footer id="footer">
  
  <div class="outer">
    <div id="footer-info" class="inner">
      &copy; 2016 John Doe<br>
      Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>
    </div>
  </div>
</footer>
    </div>
    <nav id="mobile-nav">
  
    <a href="/" class="mobile-nav-link">Home</a>
  
    <a href="/archives" class="mobile-nav-link">Archives</a>
  
</nav>
    


<script src="http://libs.baidu.com/jquery/2.0.3/jquery.min.js"></script>


  <link rel="stylesheet" href="/fancybox/jquery.fancybox.css" type="text/css">
  <script src="/fancybox/jquery.fancybox.pack.js" type="text/javascript"></script>


<script src="/js/script.js" type="text/javascript"></script>

  </div>
</body>
</html>